package com.ingenico.insider.swing.table;
import java.util.Hashtable;
import java.util.Vector;

import javax.swing.table.AbstractTableModel;

public class HashTableModel extends AbstractTableModel {
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	private Hashtable<Object, Object> hashTable;
    private Vector<Object>    hashTableKeys;
    private Vector<Object>    editableKeys;

	private String defaultKeysColumnName   = null;
	private String defaultValuesColumnName = null;

	public HashTableModel (Hashtable<Object, Object> hashTable, String keysColumnName, String valuesColumnName) {
		this (hashTable);

		setKeysColumnName  (keysColumnName);
		setValuesColumnName(valuesColumnName);
	}

	public HashTableModel (Hashtable<Object, Object> hashTable, Vector<Object> editableKeys, String keysColumnName, String valuesColumnName) {
		this (hashTable, editableKeys);

		setKeysColumnName  (keysColumnName);
		setValuesColumnName(valuesColumnName);
	}

	public HashTableModel (Hashtable<Object, Object> hashTable) {
		setHashTable(hashTable);
		setEditableKeys(null);
	}

	public HashTableModel (Hashtable<Object, Object> hashTable, Vector<Object> editableKeys) {
		setHashTable(hashTable);
		setEditableKeys(editableKeys);
	}
	
	public HashTableModel () {
		setHashTable(null);
	}

	public int getRowCount() {
		return hashTableKeys.size();
	}

	public int getColumnCount() {
		return 2;
	}

	public void setHashTable(Hashtable<Object, Object> hashTable) {
		this.hashTable = hashTable;

		if (hashTable == null) {
			hashTableKeys  = new Vector<Object>();
		} else {
			hashTableKeys  = new Vector<Object>(hashTable.keySet());
		}

		fireTableDataChanged();
	}

	/**
	 * Sets the string used in the table header for the keys column.
	 * 
	 * By default the superclass behaviour is used. If <code>null</code> is used then default behaviour is restored. 
	 * 
	 * @param keysColumnName the string to display in place of the default value or null to restore the default settings.
	 */
	public void setKeysColumnName (String keysColumnName) {
		defaultKeysColumnName = keysColumnName;
	}
	
	/**
	 * Sets the string used in the table header for the values column.
	 * 
	 * By default the superclass behaviour is used. If <code>null</code> is used then default behaviour is restored. 
	 * 
	 * @param valuesColumnName the string to display in place of the default value or null to restore the default settings.
	 */
	public void setValuesColumnName (String valuesColumnName) {
		defaultValuesColumnName = valuesColumnName;
	}

    public String getColumnName(int column) {
    	if (column > 1)
			throw new IllegalArgumentException("columnIndex out of range");
    	
    	if (column == 0) {
    		return (defaultKeysColumnName   != null) ? defaultKeysColumnName   : super.getColumnName(column);
    	} else {
    		return (defaultValuesColumnName != null) ? defaultValuesColumnName : super.getColumnName(column);
    	}
    }

	/**
	 * 
	 */
	public Object getValueAt(int rowIndex, int columnIndex) {
		Object      key = null;

		if (rowIndex > hashTable.size()) throw new IllegalArgumentException("rowIndex out of range");
		if (columnIndex > 1)             throw new IllegalArgumentException("columnIndex out of range");

		// Finds the key corresponding to the given row
		key = hashTableKeys.get(rowIndex);

		// And either return it directly or return the associated data
		if (columnIndex == 0) {
			return key;
		} else {
			return hashTable.get(key);
		}
	}

	/**
	 * 
	 */
	public void setValueAt(Object value, int rowIndex, int columnIndex) {
		Object      key = null;

		if (rowIndex > hashTable.size())
			throw new IllegalArgumentException("rowIndex out of range");

		if (columnIndex > 1)
			throw new IllegalArgumentException("columnIndex out of range");

		// Finds the key corresponding to the given row
		key = hashTableKeys.get(rowIndex);

		// And set the value in the hash table...
		hashTable.put(key, value);
	}

	/**
	 * 
	 * @param editableKeys
	 */
    public void setEditableKeys (Vector<Object> editableKeys) {
    	if (editableKeys == null) {
    		this.editableKeys = new Vector<Object>();
    	} else {
    		this.editableKeys = editableKeys;
    	}
    }

	/**
	 * 
	 */
    public boolean isCellEditable(int rowIndex, int columnIndex) {
    	// TODO: use a dictionary or any collection to set the editable mask
        if (columnIndex < 1) {
            return false;
        } else {
        	return (editableKeys.contains(hashTableKeys.get(rowIndex)));
        }
    }
}
